﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using WmsService.AOP;
using WmsService.Derived;
using WmsService.Exceptions;
using WmsService.Generate;
using WmsService.In;
using WmsService.Out;

namespace WmsService.BusinessLogic
{
    /// <summary>
    /// 出库逻辑接口
    /// </summary>
    public interface IOutStoreBillLogic
    {
        //[ServiceImplCallHandler]
        OutStoreBillWrap GetOutStoreBillWrap(string billID);

        [ValidateTokenCallHandler]
        void SaveOutStoreBillWrap(OutStoreBillWrap outStoreBillWrap);

        [ValidateTokenCallHandler]
        void AffirmOutStoreBill(string billID, DateTime? outBillDate);

        //[ServiceImplCallHandler]
        string GetOutStoreBillID();
    }

    public class OutStoreBillLogicImpl : LogicBase, IOutStoreBillLogic
    {
        //出库部分
        public Out.OutStoreBillWrap GetOutStoreBillWrap(string billID)
        {
            try
            {
                var billWrap = new OutStoreBillWrap();
                var ctx = Factory.ContextFactory.Create();
                var q = from c in ctx.OutStoreBill
                        where c.BillID == billID
                        select c;  
                var outStoreBill = q.FirstOrDefault();
                if (outStoreBill == null)
                {
                    Exceptions.ExceptionHandler.ThrowException("不存在出库单：" + billID);
                }
                ctx.Detach(outStoreBill);
                billWrap.POutStoreBill = outStoreBill;
                var q2 = from c in ctx.OutStoreBillDtl
                         where c.BillID == billID
                         select c;
                billWrap.POutStoreBillDtl = q2.ToList();
                foreach (var dtl in billWrap.POutStoreBillDtl)
                {
                    ctx.Detach(dtl);
                }
                return billWrap;
            }
            catch (Exception ex)
            {
                ExceptionHandler.ThrowException(ex);
                return null;
            }
        }

        public void SaveOutStoreBillWrap(Out.OutStoreBillWrap outStoreBillWrap)
        {
            try
            {
                var ctx = Factory.ContextFactory.Create();
                if (outStoreBillWrap.POutStoreBill.WcfEntityState == EntityState.Added)
                {
                    outStoreBillWrap.POutStoreBill.CREATETIME = DateTime.Now;
                    outStoreBillWrap.POutStoreBill.UPDATETIME = DateTime.Now;
                    outStoreBillWrap.POutStoreBill.CREATERUSERID = ContextUserID;
                    outStoreBillWrap.POutStoreBill.CREATERNAME = ContextUserName;
                    outStoreBillWrap.POutStoreBill.UPDATERNAME = ContextUserID;
                }
                else
                {
                    outStoreBillWrap.POutStoreBill.UPDATETIME = DateTime.Now;
                    outStoreBillWrap.POutStoreBill.UPDATERNAME = ContextUserID;
                }

                ctx.AddToOutStoreBill(outStoreBillWrap.POutStoreBill);
                ctx.ObjectStateManager.ChangeObjectState(outStoreBillWrap.POutStoreBill, outStoreBillWrap.POutStoreBill.WcfEntityState);
                if (outStoreBillWrap.POutStoreBillDtl != null && outStoreBillWrap.POutStoreBillDtl.Count > 0)
                {
                    foreach (var outStoreBillDtl in outStoreBillWrap.POutStoreBillDtl)
                    {
                        if (outStoreBillDtl.WcfEntityState == EntityState.Added)
                        {
                            outStoreBillDtl.CREATETIME = DateTime.Now;
                            outStoreBillDtl.UPDATETIME = DateTime.Now;
                            outStoreBillDtl.CREATERUSERID = ContextUserID;
                            outStoreBillDtl.CREATERNAME = ContextUserName;
                            outStoreBillDtl.UPDATERNAME = ContextUserID;
                        }
                        else
                        {
                            outStoreBillDtl.UPDATETIME = DateTime.Now;
                            outStoreBillDtl.UPDATERNAME = ContextUserID;
                        }
                        ctx.AddToOutStoreBillDtl(outStoreBillDtl);
                        ctx.ObjectStateManager.ChangeObjectState(outStoreBillDtl, outStoreBillDtl.WcfEntityState);
                    }
                }
                ctx.SaveChanges();
            }
            catch (Exception ex)
            {
                ExceptionHandler.ThrowException(ex);
            }
        }

        public void AffirmOutStoreBill(string billID, DateTime? outBillDate)
        {
            try
            {
                var ctx = Factory.ContextFactory.Create();
                var wrap = GetOutStoreBillWrap(billID);

                var outStoreBill = wrap.POutStoreBill;
                List<OutStoreBillDtl> outStoreBillDtls = wrap.POutStoreBillDtl;
                if (outStoreBill.BillState != Constant.BillStateDraft)
                {
                    Exceptions.ExceptionHandler.ThrowException("出库单状态为非草稿状态，不能确认出库：" + billID);
                }

                if (outBillDate == null)
                {
                    Exceptions.ExceptionHandler.ThrowException("出库确认日期为空，不能确认出库：" + billID);
                }

                //循环每一条出库记录))
                foreach (var dtl in outStoreBillDtls)
                {
                    if (dtl.Quantity == 0)
                    {
                        Exceptions.ExceptionHandler.ThrowException("出库明细物料数量不能为零！");
                    }
                    //从库存中拿到这个库存对象
                    var storeGoods = this.GetStoreGoods(dtl.NewGoodsCode, dtl.SpecificationType);

                    if (storeGoods != null)
                    {
                        //need handle 

                        storeGoods.Quantity = storeGoods.Quantity - dtl.Quantity;
                        storeGoods.AmountNotTax = storeGoods.PriceNotTax * storeGoods.Quantity;
                        storeGoods.AmountTax = storeGoods.PriceTax * storeGoods.Quantity;

                        //出库明细在出库确认的时候需要和库存保持一致的单价，税率，金额由实际的税率，单价算出
                        dtl.PriceNotTax = storeGoods.PriceNotTax;
                        dtl.PriceTax = storeGoods.PriceTax;
                        dtl.TaxRate = storeGoods.TaxRate;
                        dtl.AmountNotTax = dtl.PriceNotTax * dtl.Quantity;
                        dtl.AmountTax = dtl.PriceTax * dtl.Quantity;

                        //出库的时候，出库明细的物料代码和名称需要从库存中取出，写入到字段中：
                        //ExtVarChar3         VARCHAR(50) default '',挪用，作为该商品的供货商代码使用
	                    //ExtVarChar4         VARCHAR(50) default '',挪用，作为该商品的供货商名称使用
                        dtl.ExtVarChar3 = storeGoods.ExtVarChar1;
                        dtl.ExtVarChar4 = storeGoods.ExtVarChar2;

                        storeGoods.UPDATETIME = DateTime.Now;
                        storeGoods.UPDATERNAME = ContextUserID;

                        dtl.UPDATETIME = DateTime.Now;
                        dtl.UPDATERNAME = ContextUserID;

                        //放入上下文中
                        ctx.AddToStoreGoods(storeGoods);
                        ctx.ObjectStateManager.ChangeObjectState(storeGoods, EntityState.Modified);

                        ctx.AddToOutStoreBillDtl(dtl);
                        ctx.ObjectStateManager.ChangeObjectState(dtl, EntityState.Modified);
                    }
                    else
                    {
                        Exceptions.ExceptionHandler.ThrowException(new Exception(string.Format("库存中不存在该物料代码为：{0}，规格为：{1}，的物料，请检查库存！", dtl.NewGoodsCode, dtl.SpecificationType)));
                    }

                    if(!String.IsNullOrEmpty(dtl.ObligateChar1))
                    {
                        var q = from o in ctx.StockTackingDtl
                                where o.StockTackingDtlNo == dtl.ObligateChar1
                                select o;
                        var obj = q.FirstOrDefault();
                        if(obj != null)
                        {
                            ctx.Detach(obj);

                            obj.HandleRelateNoteNo = dtl.BillID + "序号:" + dtl.Idx.ToString();
                            obj.HandleResult ="已出" +dtl.Quantity.ToString();
                            obj.HandleTime = DateTime.Now;
                            obj.ExtNumeric1 = dtl.Quantity;
                            ctx.AddToStockTackingDtl(obj);
                            ctx.ObjectStateManager.ChangeObjectState(obj, EntityState.Modified);
                        }
                    }
                }
                outStoreBill.BillState = Constant.BillStateAffirm;//状态为确认,即已经出库
                outStoreBill.OutBillDate = outBillDate;

                ctx.AddToOutStoreBill(outStoreBill);
                ctx.ObjectStateManager.ChangeObjectState(outStoreBill, EntityState.Modified);
                ctx.SaveChanges();
            }
            catch (Exception ex)
            {
                Exceptions.ExceptionHandler.ThrowException(ex);
            }
        }

        public string GetOutStoreBillID()
        {
            try
            {
                var ctx = Factory.ContextFactory.Create();
                return ctx.ExecuteStoreQuery<String>("select dbo.GetOutStoreBillID() as BillID").FirstOrDefault();
            }
            catch (Exception ex)
            {
                Exceptions.ExceptionHandler.ThrowException(ex);
                return null;
            }
        }

// ReSharper disable MemberCanBeMadeStatic.Local
        private StoreGoods GetStoreGoods(string newGoodsCode, string specificationType)
// ReSharper restore MemberCanBeMadeStatic.Local
        {
            var ctx = Factory.ContextFactory.Create();
            List<StoreGoods> list = ctx.ExecuteStoreQuery<StoreGoods>("select * from  dbo.StoreGoods where 1=1 " + String.Format(" and NewGoodsCode = '{0}' and SpecificationType='{1}'", newGoodsCode, specificationType)).ToList();
            if (list.Count == 0)
                return null;
            return list[0];
        }
    }
}